#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np
import json
from copy import copy, deepcopy


def gensvg():
    """
    生成svg格式的棋盘, 覆盖保存到 board.svg
    """

    f = open("board.svg", "w")
    f.writelines(
        '<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="450px" height="450px" role="img" xmlns="http://www.w3.org/2000/svg">\n'
    )
    for i in range(0, 15):
        lineH = '<line x1="%d" x2="%d" y1="%d" y2="%d" stroke="#000" />\n' % (
            15, 435, 14 + 30 * i, 16 + 30 * i)
        lineV = '<line x1="%d" x2="%d" y1="%d" y2="%d" stroke="#000" />\n' % (
            14 + 30 * i, 16 + 30 * i, 15, 435)
        f.writelines(lineH)
        f.writelines(lineV)

    for i in range(0, 15):
        for j in range(0, 15):
            circle = '<circle id="%d" cx="%d" cy="%d" r="13" />\n' % (
                15 * i + j, 15 + 30 * i, 15 + 30 * j)
            f.writelines(circle)

    f.writelines('</svg>')
    f.close()


def newGame():
    """ 新开一局 """
    return np.zeros(15 * 15, dtype='int8')


def newAble():
    return np.array(range(0, 225))


def winner(vec):
    """
    通过输入数组计算胜者, 取子矩阵和核矩阵外积求和
    0 - 继续
    2 - 和
    1 - 黑
    7 - 白
    """
    mat = np.zeros((19, 19))
    mat[0:15, 0:15] = vec.reshape((15, 15))
    ks = list()
    kernel = np.zeros((5, 5))
    kernel[:, 0] = 1
    ks.append(kernel)
    kernel = np.zeros((5, 5))
    kernel[0, :] = 1
    ks.append(kernel)
    ks.append(np.eye(5))
    ks.append(np.rot90(np.eye(5)))
    for i in range(0, 15):
        for j in range(0, 15):
            Mat = mat[i:i + 5, j:j + 5]
            for k in ks:
                s = np.sum(k * Mat)
                # 黑胜
                if s == 5:
                    return 1
                # 白胜
                elif s == 35:
                    return 7

    # 继续
    if np.sum(mat) < 897:
        return 0
    # 和棋
    else:
        return 2


def turn(vec):
    """
    轮次判断
    1 - 黑
    7 - 白
    """
    s = np.sum(vec)
    if s % 2 > 0:
        return 7
    else:
        return 1


def randVs(vec, able):
    """ 
    随机落子, 返回下一步的局势和可落子位置, 函数会改变输入 vec
    vec: 当前局势
    able: 可落子位置
    """
    if len(able) < 1:
        return (vec, able)
    color = turn(vec)
    r = np.random.randint(0, len(able))
    index = able[r]
    # vec = copy(vec)
    vec[index] = color
    return (vec, np.delete(able, r))


def vs(b, w):
    """ 
    一次对局, b 执黑
    黑胜积 10 分, 和积 5 分, 负积 0 分
    白胜积 100 分, 和积 20 分, 负积 1 分
    """
    b.color = Gomoku.B
    w.color = Gomoku.W
    x = newGame()

    for i in range(0, 225):
        win = winner(x)
        if win == 0:
            color = turn(x)
            if color == b.color:
                x = b.next(x)
            else:
                x = w.next(x)

        elif win == 1:
            b.score += 10
            w.score += 1
            break
        elif win == 2:
            b.score += 5
            w.score += 20
            break
        elif win == 7:
            b.score += 0
            w.score += 100
            break

    print("vs Done.")
    return (b, w)


def array2json(arr):
    """ np.array to json """
    encoder = json.JSONEncoder()
    return encoder.encode(arr.tolist())


def json2array(jstr, dt='int8'):
    """ json to np.array with dtype = dt """
    decoder = json.JSONDecoder()
    return np.array(decoder.decode(jstr), dtype=dt)


def mcProd(vec, able, randNum=10):
    """
    蒙特卡洛算法计算下一步各位置的概率
    """
    prod = np.zeros(able.shape)
    color = turn(vec)

    # 先找出直接获胜的位置
    for i in range(0, len(able)):
        # 固定当前位置
        cv = copy(vec)
        index = able[i]
        cv[index] = color
        # 胜负判断
        win = winner(cv)
        if win == color:
            prod[i] = 1
            return prod

    # 固定当前位置后随机搜索
    for i in range(0, len(able)):
        cv = copy(vec)
        ca = copy(able)
        index = ca[i]
        cv[index] = color
        ca = np.delete(ca, i)

        # 随机落子 randNum 次, 计算获胜概率
        wc = 0
        for j in range(0, randNum):
            v = copy(cv)
            a = copy(ca)
            while True:
                (v, a) = randVs(v, a)
                win = winner(v)
                # 胜一次计数加1
                if win == color:
                    wc += 1
                    break
                # 和一次计数加0.5
                elif win == 2:
                    wc += 0.5
                    break
                # 胜率未定, 继续落子
                elif win == 0:
                    continue
                # 失败
                else:
                    break

        print("i = %d, win = %d / %d" % (i, wc, randNum))
        prod[i] = wc / randNum

    return prod
